<?php
/**
 * Sslwrap
 *
 * @package boot
 * @author  Platform Team
 */

class Sslwrap
{
    /**
     * 인스턴스
     * @var Sslwrap
     */
    private static $instance;

    /**
     * 환경설정 배열
     * @var array
     */
    private $aConfig;

    /**
     * 백엔드 API 호스트
     * @var string
     */
    private $sBackendHost;

    /**
     * 프론트엔드 API 호스트
     * @var string
     */
    private $sFrontendHost;

    /**
     * 백엔드 API 해시키
     * @var string
     */
    private $sBackendHash;

    /**
     * 프론트엔드 API 해시키
     * @var string
     */
    private $sFrontendHash;

    /**
     * 프론트엔드 SSL 사용 여부
     * @var boolean
     */
    private $isFrontendEnabled;

    /**
     * 백엔드 SSL 사용 여부
     * @var boolean
     */
    private $isBackendEnabled;

    /**
     * 테스트에 의한 호출인지 여부
     * @var boolean
     */
    private $isTest;

    /**
     * 생성자
     */
    private function __construct()
    {
        //Empty
    }

    /**
     * singleton
     *
     * @return Sslwrap
     */
    public static function getInstance()
    {
        if (!self::$instance) self::$instance = new self;

        return self::$instance;
    }

    /**
     * 인스턴스 반환
     *
     * @return Sslwrap
     */
    public static function instance()
    {
        return self::$instance;
    }

    /**
     * 인스턴스 파괴
     */
    public static function instancedel()
    {
        self::$instance = null;
    }

    /**
     * 초기화
     *
     * @param array $aConfig
     * array(
     *  'frontend_enabled' => 프론트엔드 SSL 사용여부,
     *  'backend_enabled' => 백엔드 SSL 사용여부,
     *  'frontend_hash_path' => 프론트엔드 해시키 경로,
     *  'backend_hash_path' => 백엔드 해시키 경로,
     *  'hash_manager_passwd' => 해시 매니져 API 패스워드,
     *  'frontend_encrypt_req_key' => 프론트 엔드 리퀘스트 키명,
     *  'idc_loc_path' => IDC 로케이션 경로,
     *  'in_company' => 사내서버 여부,
     *  '__test_enabled__' => TEST 활성화 여부
     * )
     */
    public function initialize($aConfig)
    {
        $this->_initConfig($aConfig);
        $this->_initEnabled();
        $this->_initBackendHost();
        $this->_initFrontendHost();
        $this->_initBackendHash();
        $this->_initFrontendHash();
    }

    /**
     * 암호화 - 프론트엔드
     * 비활성화시 원본데이터 반환
     *
     * @param mixed $mData
     * @return utilSslwrapException | string
     */
    public function encryptFrontend($mData)
    {
        if ($this->isFrontendEnabled !== true) {
            return $mData;
        }

        return utilSslwrapFrontend::encrypt($this->sFrontendHost, $mData);
    }

    /**
     * 복호화 - 프론트엔드
     * 비활성화시 원본데이터 반환
     *
     * @param string $sData
     * @return utilSslwrapException | mixed
     */
    public function decryptFrontend($sData)
    {
        if ($this->isFrontendEnabled !== true) {
            return $sData;
        }

        return utilSslwrapFrontend::decrypt($this->sFrontendHost, $sData, $this->sFrontendHash);
    }

    /**
     * 암호화 - 백엔드
     * 비활성화시 원본데이터 반환
     *
     * @param mixed  $mData
     * @param string $sType
     * @return utilSslwrapException | string
     */
    public function encryptBackend($mData, $sType)
    {
        if ($this->isBackendEnabled !== true) {
            return $mData;
        }

        return utilSslwrapBackend::encrypt($this->sBackendHost, $mData, $this->sBackendHash, $sType);
    }

    /**
     * 복호화 - 백엔드
     * 비활성화시 원본데이터 반환
     *
     * @param string $sData
     * @param string $sType
     * @param string $sFromIp
     * @return utilSslwrapException | mixed
     */
    public function decryptBackend($sData, $sType, $sFromIp=null)
    {
        if ($this->isBackendEnabled !== true) {
            return $sData;
        }

        return utilSslwrapBackend::decrypt($this->sBackendHost, $sData, $this->sBackendHash, $sType, $sFromIp);
    }

    /**
     * 프론트엔드 API 호스트
     *
     * @return string | false
     */
    public function getFrontendHost()
    {
        return $this->sFrontendHost;
    }

    /**
     * 백엔드 API 호스트
     *
     * @return string | false
     */
    public function getBackendHost()
    {
        return $this->sBackendHost;
    }

    /**
     * 프론트엔드 암호화 문자열 리퀘스트 키
     *
     * @return string
     */
    public function getFrontendEncryptReqKey()
    {
        return $this->aConfig['frontend_encrypt_req_key'];
    }

    /**
     * 프론트엔드 암호화 리퀘스트 UNSET 키
     *
     * @return string
     */
    public function getFrontendEncryptReqUnset()
    {
        return '#@#Sslwrap-UNSET#@#';
    }

    /**
     * 프론트엔드 암호화된 배열 리퀘스트 접두어키
     *
     * @return string
     */
    public function getFrontendEncryptReqArrValuePrefix()
    {
        return 'Sslwrap@@';
    }

    /**
     * 프론트엔드 암호화된 배열 리퀘스트 구분자키
     *
     * @return string
     */
    public function getFrontendEncryptReqArrValueSep()
    {
        return '(+|-+|+-|+)';
    }

    /**
     * 프론트엔드 활성화 여부
     *
     * @return boolean
     */
    public function isFrontendEnabled()
    {
        return $this->isFrontendEnabled;
    }

    /**
     * 백엔드 활성화 여부
     *
     * @return boolean
     */
    public function isBackendEnabled()
    {
        return $this->isBackendEnabled;
    }

    private function _initConfig($aConfig)
    {
        $this->aConfig = array();

        $this->aConfig['frontend_enabled']         = ($aConfig['frontend_enabled'] === true) ? true : false;
        $this->aConfig['backend_enabled']          = ($aConfig['backend_enabled'] === true) ? true : false;
        $this->aConfig['frontend_encrypt_req_key'] = $aConfig['frontend_encrypt_req_key'];
        $this->aConfig['hash_manager_passwd']      = $aConfig['hash_manager_passwd'];
        $this->aConfig['idc_loc_path']             = $aConfig['idc_loc_path'];
        $this->aConfig['frontend_hash_path']       = $aConfig['frontend_hash_path'];
        $this->aConfig['backend_hash_path']        = $aConfig['backend_hash_path'];
        $this->aConfig['in_company']               = ($aConfig['in_company'] === true) ? true : false;

        $this->isTest                              = ($aConfig['__test_enabled__'] === true) ? true : false;
    }

    private function _initEnabled()
    {
        $this->isFrontendEnabled = $this->aConfig['frontend_enabled'];
        $this->isBackendEnabled = $this->aConfig['backend_enabled'];
    }

    private function _initBackendHost()
    {
        if ($this->isBackendEnabled === true) {
            if ($this->aConfig['in_company'] === true) {
                $this->sBackendHost = 'https://sapi-000.cafe24.com';
            } else {
                $this->sBackendHost = 'https://sapi.cafe24.com';
            }
        } else {
            $this->sBackendHost = false;
        }
    }

    private function _initFrontendHost()
    {
        if ($this->isFrontendEnabled === true) {
            if ($this->aConfig['in_company'] === true) {
                $this->sFrontendHost = 'http://192.168.51.47';
            } else {
                $this->sFrontendHost = 'https://' . utilSslwrapFrontend::getHostByIDC($this->aConfig['idc_loc_path']);
            }
        } else {
            $this->sFrontendHost = false;
        }
    }

    private function _initBackendHash()
    {
        if ($this->isBackendEnabled !== true) {
            $this->sBackendHash = false;
            return;
        }

        $this->sBackendHash = utilSslwrapBackend::readHash($this->aConfig['backend_hash_path']);

        if (FW_OS_UNIX === true && $this->isTest === false) {
            if ($this->sBackendHash === false) {
                throw new Exception('[Sslwrap] Backend hash file not found on server', E_USER_ERROR);
            }
            return;
        }

        if ($this->sBackendHash === false) {
            if (touch($this->aConfig['backend_hash_path']) === false) {
                throw new Exception('[Sslwrap] Can not create a backend hash file', E_USER_ERROR);
            }

            utilSslwrapBackend::expireHash($this->sBackendHost, $this->aConfig['hash_manager_passwd'], $this->aConfig['backend_hash_path']);
            $r = utilSslwrapBackend::createHash($this->sBackendHost, $this->aConfig['hash_manager_passwd'], $this->aConfig['backend_hash_path']);

            if ($r !== true) {
                throw new Exception('[Sslwrap] Failed to create a backend hash file - msg : ' . $r->getMessage(), E_USER_ERROR);
            }

            $this->sBackendHash = utilSslwrapBackend::readHash($this->aConfig['backend_hash_path']);
        }
    }

    private function _initFrontendHash()
    {
        if ($this->isFrontendEnabled !== true) {
            $this->sFrontendHash = false;
            return;
        }

        $this->sFrontendHash = utilSslwrapFrontend::readHash($this->aConfig['frontend_hash_path']);

        if (FW_OS_UNIX === true && $this->isTest === false) {
            if ($this->sFrontendHash === false) {
                throw new Exception('[Sslwrap] Frontend hash file not found on server', E_USER_ERROR);
            }
            return;
        }

        if ($this->sFrontendHash === false) {
            if (touch($this->aConfig['frontend_hash_path']) === false) {
                throw new Exception('[Sslwrap] Can not create a frontend hash file', E_USER_ERROR);
            }

            utilSslwrapFrontend::expireHash($this->sFrontendHost, $this->aConfig['hash_manager_passwd'], $this->aConfig['frontend_hash_path']);
            $r = utilSslwrapFrontend::createHash($this->sFrontendHost, $this->aConfig['hash_manager_passwd'], $this->aConfig['frontend_hash_path']);

            if ($r !== true) {
                throw new Exception('[Sslwrap] Failed to create a frontend hash file - msg : ' . $r->getMessage(), E_USER_ERROR);
            }

            $this->sFrontendHash = utilSslwrapFrontend::readHash($this->aConfig['frontend_hash_path']);
        }
    }


}
